package dao;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.NoResultException;
import javax.persistence.Persistence;

import model.Behandling;
import model.Delbehandling;
import model.LagerOmraade;

public class JpaDAO implements DAO {
	private static JpaDAO dao;

	public static JpaDAO getDAO() {
		if (dao == null)
			dao = new JpaDAO();
		return dao;
	}

	private EntityManagerFactory emf = 
		Persistence.createEntityManagerFactory("JpaDAO test");
	private EntityManager em = emf.createEntityManager();
	private EntityTransaction tx = em.getTransaction();

	private JpaDAO () {
		// singleton
	}

	@Override
	public synchronized <T> T find(Class<T> clazz, Object id) {
		return em.find(clazz, id);
	}

	@Override
	public synchronized <T> List<T> get(Class<T> clazz) {

		if (clazz.equals(Behandling.class)) { //medtag ikke behandlinger markeret som slettet
			return em.createNamedQuery("Behandling.findAlle", clazz).getResultList(); 
		} else {
			return em.createQuery("SELECT e FROM " + 
					clazz.getSimpleName() + " e", clazz).getResultList();
		}    
	}

	@Override
	public synchronized <T> void persist(T object) {
		boolean wasalreadyactive = tx.isActive();
	    if ( !wasalreadyactive ){
		    tx.begin();
		}    
		
		em.persist(object);
		
		if ( !wasalreadyactive ){
		    tx.commit();
		}
	}

	@Override
	public synchronized void update() { // updates all managed entities
	    if ( !tx.isActive() ){
	        tx.begin();
	        tx.commit();
	    }
	}

	@Override
	public synchronized <T> void remove(T managed) {
	    boolean wasalreadyactive = tx.isActive();
	    if ( !wasalreadyactive ){
		    tx.begin();
		}
		em.remove(managed);
		if ( !wasalreadyactive ){
		    tx.commit();
		}    
	}

	@Override
	public synchronized void clear() {
		em.clear();
	}

	@Override
	public synchronized void transactionBegin() throws RuntimeException  {
	    if ( ! isTransactionActive() ) {
	        tx.begin();
	    } else {
            throw new RuntimeException("Der var allerede en aktiv transaction.");
        }    
	}

	@Override
	public synchronized void transactionCommit() throws RuntimeException  {
	    if ( isTransactionActive() ) {
	        tx.commit();
	    } else {
            throw new RuntimeException("Der var ingen transaction begyndt.");
        }    
	}

	@Override
	public synchronized void transactionRollback() throws RuntimeException {
		if ( isTransactionActive() ) {
		    tx.rollback();
		} else {
		    throw new RuntimeException("Der var ingen transaction begyndt.");
		}
	}

	
	@Override
	public synchronized boolean isTransactionActive() {
	    return tx.isActive();
	}
	
	/**
	 * Martin Hansen
	 */
	public synchronized LagerOmraade findLagerOmraadePaaNavn(String navn) {
		try {
			return em.createNamedQuery("LagerOmraade.findLagerOmraadePaaNavn", LagerOmraade.class).setParameter("navn", navn).getSingleResult();
		} catch (NoResultException nre) {
			return null;
		}
	}

	@Override
	public synchronized Delbehandling findDelbehandlingPaaNavn(String navn) {
	    try {
            return em.createNamedQuery("Delbehandling.findPaaNavn", Delbehandling.class).setParameter("navn", navn).getSingleResult();
        } catch (NoResultException e) {
            return null;
        }
	}

	@Override
    public synchronized Behandling findBehandlingPaaNavn(String navn) {
	    try {
            return em.createNamedQuery("Behandling.findPaaNavn", Behandling.class).setParameter("navn", navn).getSingleResult();
        } catch (NoResultException e) {
            return null;
        }
    }

    @Override
    public synchronized List<String> getAlleProduktTyperFraBehandling() {
        return em.createNamedQuery("Behandling.findAlleProduktTyper", String.class).getResultList();
    }

    @Override
    public synchronized List<Behandling> getAlleBehandlingPaaProduktType(String produktType) {
        return em.createNamedQuery("Behandling.findAllePaaProduktType", Behandling.class).setParameter("produktType", produktType).getResultList();
    }

    @Override
    public synchronized <T> void merge(T object) {
        boolean wasalreadyactive = tx.isActive();
        if ( !wasalreadyactive ){
            tx.begin();
        }
        em.merge(object);
        if ( !wasalreadyactive ){
            tx.commit();
        }    
        
    }
    
    
}
